import Vue, { VNode } from 'vue'
import Component from 'vue-class-component'
// import { IMAGE_PATH } from '@/config'
// import Cookies from 'js-cookie'
// import event from '@/utils/events'
// import {
//   getBase64
// } from '@/utils/tools'
import { isObject, merge, pickBy } from 'lodash-es'
import SelectExportField from '@/components/src/SelectExportField'
import SelectTableHeader from '@/components/src/SelectTableHeader/index'
import { Form, message, Modal } from 'ant-design-vue'
import { AxiosRequestConfig } from 'axios'

export interface ISort {
  order: OrderEnum
  columnKey: string
}

export enum OrderEnum {
  ASCEND = 'ascend',
  DESCEND = 'descend',
}

@Component({
  components: {
    SelectExportField,
  },
})
export class TableMixin extends Vue {
  /**
   * 分页相关参数模块
   *
   * @memberof TableMixin
   */
  // 数据总条数
  public total: number = 0
  // 分页数大小
  public pageSize: number = 50
  // 当前页码
  public currentPage: number = 1
  // 可选页数大小
  public pageSizes: string[] = ['20', '50', '80', '100']
  // ant-design-vue 分页配置
  public pagination: any = {}
  // 本地排序
  public isLocalSort = false
  // 表格大小
  public size: string = 'middle'

  // 排序
  public sorts: Record<string, number> = {}

  // 表头
  public columns: any[] = []
  // 是否显示索引列
  public isShowIndexColumn = true
  // 是否包含统计列表
  public hasTotalRow = false
  // tableColumns
  get tableColumns() {
    const columns = this.columns.filter(
      (column: ITable.IColumn) =>
        !column.form ||
        typeof column.form.isShowList === 'undefined' ||
        column.form.isShowList
    )
    this.flatTableColumns = columns
      .map((column) => column.children || column)
      .flat()
    if (this.isShowIndexColumn) {
      columns.unshift({
        title: '序号',
        dataIndex: 'index',
        key: 'index',
        align: 'center',
        width: 50,
        customRender: (text: unknown, record: unknown, index: number) =>
          `${
            this.hasTotalRow && index === 0
              ? ''
              : index + (this.hasTotalRow ? 0 : 1)
          }`,
      })
    }
    return columns
  }

  // get showFields () {
  //   return this.tableColumns.filter(column => column.)
  // }

  // 扁平化后的列表数据
  // @bug (修复table多级表头getLabel异常问题)
  public flatTableColumns: ITable.IColumn[] = []
  // 列表数据
  public tableData: any[] = []
  // 表格加载效果
  public tableLoading: boolean = false
  // 搜索参数
  public tableSearch: any = {}
  // 公共提交参数
  public commonParams: any = {}

  // 搜索列
  get searchColumns() {
    return this.columns
      .map((column) => column.children || column)
      .flat()
      .filter(
        (column: ITable.IColumn) => column.form && column.form.isShowQuery
      )
  }

  // 接口方法对象
  public tableApi: any = {
    list: '',
    add: '',
    edit: '',
    del: '',
    dels: '',
    imageUpload: '',
    imageRemove: '',
    import: '',
  }
  // 多选
  public selectedRowKeys: any[] = []
  public selectedRows: any[] = []
  // 当前选中行
  public currentRow: any = {}
  // 当前选中行原引用
  public currentRowRef: any = {}
  // 多选数组
  public selectArr: any = []

  /**
   * 表单相关
   *
   * @memberof TableMixin
   */
  // 是否显示弹窗
  public visible: boolean = false
  // 表单标题
  public visibleTitle: string = ''
  // 表单提交按钮加载效果
  public visibleLoading: boolean = false
  // 当前表单模式
  public formMode: string = ''
  // 表单对象
  public visibleForm: Form | any = null
  // 表单元素布局
  public formItemLayout = {
    labelCol: { span: 5 },
    wrapperCol: { span: 18 },
  }
  // 列表字段
  get formColumns() {
    const columns = this.columns
      .map((column) => column.children || column)
      .flat()
      .filter(
        (column: ITable.IColumn) =>
          column.form &&
          (typeof column.form.isShowFrom === 'undefined' ||
            column.form.isShowFrom)
      )
    return columns
  }

  // 自定义列表选择框宽度
  public columnWidth: string | number = '60px'
  // 多选/单选，checkbox or radio
  public selectedType: string = 'checkbox'
  public selectedTitle: string | VNode = ''
  // 自定义配置项
  public customRowSelectionOptions = {}
  get rowSelection() {
    if (this.customRowSelectionOptions === false) return null
    return {
      columnTitle: this.selectedTitle,
      selectedRowKeys: this.selectedRowKeys,
      hideDefaultSelections: true,
      fixed: true,
      selections: [
        {
          key: 'all-data',
          text: '当页全选',
          onSelect: (keys: string[]) => {
            this.selectedRowKeys = keys
          },
        },
        {
          key: 'cancel',
          text: '当页取消',
          onSelect: () => {
            this.selectedRowKeys = []
          },
        },
      ],
      type: this.selectedType,
      columnWidth: this.columnWidth,
      onChange: (selectedRowKeys: any[], selectedRows: any[]) => {
        this.selectedRowKeys = selectedRowKeys
        this.selectedRows = selectedRows
      },
      ...this.customRowSelectionOptions,
    }
  }

  set rowSelection(val) {
    this.rowSelection = val
  }

  /**
   * 支持自定义Row
   *
   * @memberof TableMixin
   */
  public customRow!: (record: any) => unknown
  // 定义行双击事件
  public customTableRow = (record: any) => {
    return merge(
      {
        on: {
          dblclick: (e: Event) => {
            console.log('dblclick =>', e, record)
            e.preventDefault()
            e.stopPropagation()
            if (typeof record.isDblClick === 'undefined') {
              this.$set(record, 'isDblClick', false)
            }
            console.log(record.isDblClick)
            record.isDblClick = !record.isDblClick
          },
        },
        class: {
          'dblclick-heightlight': record.isDblClick,
        },
      },
      this.customRow ? this.customRow(record) : {}
    )
  }

  public $refs: any

  public showTotal(total: number) {
    return `共 ${total} 条`
  }

  // table窗口高度
  get tableClientHeight() {
    const height = document.documentElement.clientHeight - 444
    return height < 200 ? 200 : height
  }

  public created() {
    //
  }

  public mounted() {
    //
    this.visibleForm = this.$refs['custom-form']
    // 初始化查询字段
    // this.searchColumns.forEach((column: ITable.IColumn) => {
    //   this.$set(this.tableSearch, column.key, '')
    // })
    this.initTableHeaderContextMenu()
  }

  // 初始化表头右键操作
  public initTableHeaderContextMenu() {
    document
      .querySelector('.ant-table-thead')
      ?.addEventListener('contextmenu', (e) => {
        console.log(e)
        // SelectTableHeader()
        e.preventDefault()
      })
  }

  public getData() {
    //
  }

  public search() {
    this.currentPage = 1
    this.getData()
  }

  // ant-design-vue table改变事件
  public handleTableChange(pagination: any, filters: any, sorter: any) {
    let { columnKey, order } = sorter
    if (this.isLocalSort) {
      if (!order) {
        columnKey = 's_a_id'
        order = 'ascend'
      }

      function format(str: any) {
        // 移除金额内的逗号
        if (!str || typeof str !== 'string') return str
        return str.replace(',', '')
      }

      // 统计行不参与排序
      if (this.hasTotalRow) {
        this.tableData = [
          this.tableData[0],
          ...this.tableData.slice(1).sort((a, b) => {
            return order === 'ascend'
              ? format(a[columnKey]) - format(b[columnKey])
              : format(b[columnKey]) - format(a[columnKey])
          }),
        ]
      } else {
        this.tableData.sort((a, b) => {
          return order === 'ascend'
            ? format(a[columnKey]) - format(b[columnKey])
            : format(b[columnKey]) - format(a[columnKey])
        })
      }
    } else {
      this.sorts = {}
      const key = columnKey + '_sort'
      if (!order) {
        delete this.sorts[key]
      } else {
        this.sorts[key] = OrderEnum.ASCEND === order ? 1 : 2
      }

      this.getData()
    }
    // const pager = { ...this.pagination }
  }

  /**
   * 修改当前页码事件
   *
   * @param {*} index
   * @memberof TableMixin
   */
  public changePage(index: any) {
    this.currentPage = index
    this.getData()
  }

  /**
   * 修改pageSize触发事件
   *
   * @param {number} index 当前页码
   * @param {number} [size] 切换后的pageSize
   * @memberof TableMixin
   */
  public changePageSize(index: number, size?: number) {
    // 兼容之前的调用，完全替换后再移除
    this.pageSize = size || index
    this.currentPage = 1
    this.getData()
  }

  // 多选
  public handleSelectionChange(val: any) {
    this.selectArr = val
  }

  // 批量选择合并成字符串 传入name为选择的字段
  public handleSelect(currentRow: any, name: string) {
    this.selectArr = currentRow.map((item: any) => item[name])
    this.selectArr = this.selectArr.join(',')
  }

  // 批量选择合并成数组 传入name为选择的字段
  public handleSelectArr(currentRow: any, name: string) {
    this.selectArr = currentRow.map((item: any) => item[name])
    console.log(this.selectArr)
  }

  /**
   * 修改列表字典
   *
   * @param {string} key
   * @param {any[]} [dict=[]]
   * @memberof TableMixin
   */
  public changeDict(key: string, dict: any[] = [], field: string = 'dict') {
    this.columns.forEach((column: ITable.IColumn) => {
      if (key === column.key && column.form) {
        this.$set(column.form, field, dict)
      }
    })
  }

  /**
   * 获取字典label
   *
   * @param {string} key
   * @param {any[]} [dict=[]]
   * @returns
   * @memberof TableMixin
   */
  public getLabel(
    value: string,
    dict: ITable.IDictOption[] = [],
    key?: string
  ) {
    if (!value) return
    const values = `${value}`.split(',')
    let column: ITable.IColumn | undefined = undefined
    // 自动到表头找字典
    if (key && !dict.length) {
      column = this.flatTableColumns.find((item) => item.key === key)
    }
    const arr = (column && column.form && column.form.dict) || dict
    const dicts = arr.filter((item) => values.includes(`${item.value}`))
    return dicts.length ? dicts.map((item) => item.label).join(',') : value
  }

  /**
   * 获取table列表数据
   *
   * @param {object} extra 额外参数
   * @memberof TableMixin
   */
  public async getTableList(extra: Record<string, string> = {}) {
    // 处理排序字段
    // this.sorts

    let params = Object.assign(
      {},
      {
        ...this.commonParams,
        ...this.tableSearch,
        page: this.currentPage,
        pageSize: this.pageSize,
      },
      this.sorts,
      extra
    )
    this.tableLoading = true
    try {
      const res = await this.tableApi.list(params, {
        allowParams: Object.keys(this.tableSearch),
      })
      this.tableLoading = false
      this.total = +res.data.num || 0
      this.tableData = res.data.data || []
      return res
    } catch (err) {
      this.tableLoading = false
      throw err
    }
  }

  /**
   * 删除单体数据
   *
   * @param {object} params 删除的数据对象
   * @memberof TableMixin
   */
  public async tableDel(params: object) {
    try {
      const res = await this.tableApi.del(
        {
          ...this.commonParams,
          ...params,
        },
        { loading: true }
      )
      message.success('删除成功')
      this.getData()
    } catch (err) {
      throw err
    }
  }

  /**
   * 多选删除
   *
   * @param {*} params
   * @memberof TableMixin
   */
  public tableDels(params: object) {
    if (!this.selectedRowKeys.length) {
      message.warning('请先至少选择一条数据')
      return
    }
    this.$confirm({
      title: '删除提示',
      content: '确定删除选中的数据吗?',
      onOk: () => {
        return new Promise((resolve, reject) => {
          this.tableApi
            .dels(
              {
                ...params,
                ...this.commonParams,
              },
              { loading: true }
            )
            .then((res: Api.ResponseOptions) => {
              this.selectedRowKeys = []
              message.success('删除成功')
              this.getData()
              resolve(res)
            })
        })
      },
    })
  }

  /**
   * 添加数据
   *
   * @memberof TableMixin
   */
  public tableAdd() {
    this.visible = true
    this.visibleTitle = '添加'
    this.formMode = 'add'
    this.$nextTick(() => {
      const instances = this.$refs['custom-form']
      console.log(instances, 'instances', this)
      if (Array.isArray(instances)) {
        instances.forEach(instance => instance.resetFields()) 
      } else {
        instances.resetFields()
      }
    })
  }

  /**
   * 编辑数据
   *
   * @param {object} row
   * @memberof TableMixin
   */
  public tableEdit(row: object) {
    this.visible = true
    this.formMode = 'edit'
    this.visibleTitle = '编辑'
    this.$nextTick(() => {
      this.currentRow = Object.assign({}, row)
    })
  }

  /**
   * 查看
   *
   * @param {Record<string, string>} row
   * @memberof TableMixin
   */
  public tablePreview(row: object) {
    this.visible = true
    this.formMode = 'preview'
    this.visibleTitle = '查看'
    this.$nextTick(() => {
      this.currentRow = Object.assign({}, row)
    })
  }

  /**
   * 提交前表单验证
   *
   * @param {Event} e
   * @memberof TableMixin
   */
  public async handleSubmit(
    options = {},
    isRefresh?: boolean,
    format?: (params: any) => void
  ) {
    let result = await this.$refs['custom-form'].submit()
    // 提交前拦截参数
    if (format) {
      result = await format(result)
    }

    if (this.formMode === 'add') {
      return this.addApi(result, options, isRefresh)
    } else if (this.formMode === 'edit') {
      return this.editApi(result, options, isRefresh)
    }
  }

  /**
   * 调用添加接口提交数据
   *
   * @param {object} [values={}]
   * @memberof TableMixin
   */
  public addApi(values: object = {}, options = {}, isRefresh = true) {
    let params = Object.assign(
      {},
      {
        ...this.commonParams,
        ...pickBy(values, Boolean),
      }
    )
    this.visibleLoading = true
    return this.tableApi
      .add(params, { loading: false, ...options })
      .then((res: Api.ResponseOptions) => {
        this.visible = false
        setTimeout(() => {
          message.success('添加成功')
          isRefresh && this.getData()
        }, 200)
      })
      .finally(() => {
        this.visibleLoading = false
      })
  }

  /**
   * 调用编辑接口提交数据
   *
   * @param {object} [values={}]
   * @memberof TableMixin
   */
  public editApi(values: object = {}, options = {}, isRefresh = true) {
    let params = Object.assign(
      {},
      {
        ...this.currentRow,
        ...this.commonParams,
        ...values,
      }
    )
    this.visibleLoading = true
    return this.tableApi
      .edit(params, { loading: false, ...options })
      .then((res: Api.ResponseOptions) => {
        this.visible = false
        setTimeout(() => {
          Modal.success({
            centered: true,
            content: "编辑成功"
          })
          // message.success('编辑成功')
          isRefresh && this.getData()
        }, 200)
      })
      .finally(() => {
        this.visibleLoading = false
      })
  }

  /**
   * 删除图片
   *
   * @param {number} id 图片id
   * @param {string} key 图片key
   * @param {() => void} resolve
   * @memberof TableMixin
   */
  public tableImageRemove(id: number, key: string, resolve: () => void) {
    let params = {
      type: key,
      g_img_id: id,
    }
    this.$api[this.tableApi.imageRemove](
      Object.assign(this.currentRow, params)
    ).then((res: Api.ResponseOptions) => {
      message.success(res.data)
      resolve()
    })
  }

  /**
   * 图片上传
   *
   * @param {{ file: File, key: string }} fileParams 文件参数
   * @param {string[]} keys 从当前Row数据中提取的key值
   * @param {(url: string) => void} resolve
   * @memberof TableMixin
   */
  public async tableImageUpload(
    fileParams: { file: File; key: string },
    keys: string[],
    resolve: (data: any) => void,
    isBase64: boolean = false
  ) {
    let params: any
    let config = {}
    // if (isBase64) {
    //   const base64 = await getBase64(fileParams.file)
    //   params = {
    //     img: base64,
    //     type: fileParams.key
    //   }
    //   keys.forEach((key: string) => {
    //     params[key] = this.currentRow[key]
    //   })
    // } else {
    //   params = new FormData()
    //   params.append('img', fileParams.file)
    //   params.append('type', fileParams.key)
    //   keys.forEach((key: string) => {
    //     params.append(key, this.currentRow[key])
    //   })
    //   config = {
    //     headers: {
    //       'Content-Type': 'multipart/form-data'
    //     }
    //   }
    // }
    this.$api[this.tableApi.imageUpload](params, config).then(
      (res: Api.ResponseOptions) => {
        message.success('上传完成')
        if (isBase64) {
          resolve({
            id: -1,
            url: params.img,
          })
        } else {
          resolve(res.data)
        }
      }
    )
  }

  /**
   * 按查询条件导出当前列表数据
   *
   * @memberof TableMixin
   */
  public exportLoading = false
  public requireExportFields: string[] = []
  public tableExportExecl<
    F = (data: Record<string, string>) => Promise<unknown>
  >(
    extra: Record<string, string> = {},
    options:
      | boolean
      | {
          defaultAll: boolean
          isFlatColumn: boolean
          fields: Array<
            ITable.IDictOption & { disabled: boolean; selected: boolean }
          >
        } = false,
    componentOptions?: {
      isSupportSort?: boolean
      title?: string
    }
  ) {
    // 配置项
    let customOptions: {
      defaultAll: boolean
      isFlatColumn: boolean
      fields: Array<
        ITable.IDictOption & { disabled: boolean; selected: boolean }
      >
    } = {
      defaultAll: false,
      isFlatColumn: false,
      fields: [],
    }

    // 组件配置项
    let customComponentOptions = {
      isSupportSort: true,
      title: '',
    }

    if (componentOptions && isObject(componentOptions)) {
      customComponentOptions = {
        ...customComponentOptions,
        ...(componentOptions || {}),
      }
    }

    if (typeof options === 'boolean') {
      customOptions.defaultAll = options
    } else {
      customOptions = {
        ...customOptions,
        ...options,
      }
    }

    // 支持自定义导出字段
    if (!customOptions.fields || !customOptions.fields.length) {
      // @ts-ignore
      customOptions.fields = this.columns
        .filter(
          (column: ITable.IColumn) =>
            !column.form ||
            (typeof column.form.isExport !== 'undefined'
              ? column.form.isExport
              : typeof column.form.isShowList === 'undefined' ||
                column.form.isShowList)
        )
        // .map(column => column.children || column)
        // .flat()
        .map((column) => {
          // action 操作列表
          if (!column.key || column.key === 'action') return null
          return {
            label: column.title || column.titleAlias,
            value: column.key,
            disabled: this.requireExportFields.includes(column.key),
            selected: this.requireExportFields.includes(column.key),
          }
        })
        .filter((_) => _)
        // @ts-ignore
        .sort((a, b) => b.disabled - a.disabled)
    }

    // 默认全选者不显示选择界面
    if (customOptions.defaultAll) {
      return this.exportExecl(
        customOptions.fields.map((item) => item?.value) as string[],
        extra
      )
    }

    return new Promise((resolve, reject) => {
      const _self = this
      this.$dialog(
        SelectExportField,
        {
          fields: customOptions.fields,
          isSupportSort: customComponentOptions.isSupportSort,
        },
        {
          title: customComponentOptions.title || '导出Execl配置选择',
          width: '1100px',
          confirmLoading: this.exportLoading,
          on: {
            ok() {
              console.log('导出')
              // @ts-ignore
              let selected = !customComponentOptions.isSupportSort
                ? // @ts-ignore
                  this.$refs._component.currentSelected
                : // @ts-ignore
                  this.$refs._component.currentSortedFields.map((_) => _.value)
              // @ts-ignore
              const type = this.$refs._component.currentType
              if (!selected.length) {
                message.error('请选择导出字段')
                reject();
                return false
              }

              // 自动保持默认排序
              if (!customComponentOptions.isSupportSort) {
                selected = customOptions.fields
                  .map((item) => item.value)
                  .filter((val) => selected.includes(val))
              }
              _self.exportExecl(selected, {
                ...extra,
                exportExeclMode: type,
              }).then(resolve, reject)
            },
            cancel() {
              console.log('cancel export')
              reject()
            }
          },
        }
      )
    })
  }

  public exportExecl(keys: string[], extra: Record<string, string> = {}) {
    const loading = message.loading({
      duration: 0,
      content: '数据正在导出。。。请稍后',
    })
    this.exportLoading = true
    if (this.tableApi.exportExecl) {
      let params: Record<string, string> = Object.assign(
        {},
        {
          ...this.commonParams,
          ...this.tableSearch,
          page: this.currentPage,
          pageSize: this.pageSize,
        },
        this.sorts,
        extra
      )
      return this.tableApi
        .exportExecl({
          ...params,
          keys,
        })
        .then((_: AxiosRequestConfig) => {
          // 判断是否异常
          if (_.data.type === 'application/json') {
            const reader = new FileReader()
            reader.readAsText(_.data, 'utf-8')
            reader.onload = () => {
              const data = JSON.parse(reader.result as string)
              message.error(data.msg)
            }
          } else {
            // @ts-ignore
            const filename = _.headers['content-disposition']
              .replace(/(.*)(?=filename=)/g, '')
              .replace('filename=', '')
            const data = _.data
            const url = window.URL.createObjectURL(data)
            const link = document.createElement('a')
            link.style.display = 'none'
            link.href = url
            link.setAttribute('download', decodeURI(filename))
            document.body.appendChild(link)
            link.click()
            document.body.removeChild(link)
          }
        })
        .finally(() => {
          loading()
          this.exportLoading = false
        })
    } else {
      throw new Error('导出接口未定义')
    }
  }
}
